package com.cms.plugin.services.impl;

import com.cms.common.hook.enums.PluginsTypeEnum;
import com.cms.common.model.entity.Plugin;
import com.cms.common.repository.PluginRepository;
import com.cms.config.PluginConfig;
import com.cms.plugin.services.PluginService;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.gitee.starblues.core.PluginInfo;
import com.gitee.starblues.integration.operator.PluginOperator;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.File;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.*;

@Service
public class PluginServiceImpl implements PluginService {

    @Autowired
    private PluginRepository pluginRepository;

    @Autowired
    private ObjectMapper objectMapper;

    @Autowired
    PluginOperator pluginOperator;

    @Override
    public List<Plugin> findAll() {

        //自己加入的插件包
        loadZips("plugins-feature");

        // 获取已加载的所有的插件
        List<PluginInfo> pluginInfos = pluginOperator.getPluginInfo();
        Collections.sort(pluginInfos, new Comparator<PluginInfo>() {
            @Override
            public int compare(PluginInfo u1, PluginInfo u2) {//排序
                int diff = u1.getPluginId().hashCode() - u2.getPluginId().hashCode();
                if (diff > 0) {
                    return 1;
                } else if (diff < 0) {
                    return -1;
                }
                return 0;
            }
        });
        Map<String, Plugin> pluginMap = new HashMap<>();
        List<Plugin> plugins = pluginRepository.findAll();
        for (Plugin plugin : plugins) {
            pluginMap.put(plugin.getPluginId(), plugin);
        }
        List<Plugin> pluginInfoList = new ArrayList<>();
        for (PluginInfo pluginInfo : pluginInfos) {

            Plugin plugin = pluginMap.get(pluginInfo.getPluginId());
            if (plugin == null) {
                plugin = new Plugin();
                plugin.setPluginId(pluginInfo.getPluginId());
                plugin.setName(pluginInfo.getPluginDescriptor().getDescription());
                plugin.setDescription(pluginInfo.getPluginDescriptor().getDescription());
                plugin.setAuthor(pluginInfo.getPluginDescriptor().getProvider());
                plugin.setVersion(pluginInfo.getPluginDescriptor().getPluginVersion());
                //plugin.setConfig(JSON.toJSONString(pluginInfo.getExtensionInfo()));
                String packageName = pluginInfo.getPluginId() + "-" + pluginInfo.getPluginDescriptor().getPluginVersion() + "-repackage" + ".zip";
                plugin.setPackageName(packageName);
                plugin.setEnabled(false);
                String pluginPath = pluginInfo.getPluginDescriptor().getPluginPath();
                for (PluginsTypeEnum pluginsTypeEnum : PluginsTypeEnum.values()) {
                    if (pluginPath.indexOf(File.separatorChar + pluginsTypeEnum.getPluginDir() + File.separatorChar) > -1) {
                        plugin.setType(pluginsTypeEnum.getPluginDir());
                        break;
                    }
                }
                plugin = pluginRepository.saveAndFlush(plugin);
            }
            pluginInfoList.add(plugin);
        }


        return pluginInfoList;
    }

    private void loadZips(String type) {
        String dirPath = PluginConfig.zipPath + "/" + type;
        List<String> zipFiles = scanFiles(dirPath, ".zip");
        for (String fileName : zipFiles) {
            //TODO 优化获取这个pluginID的方式(解压包，再读取里面的配置)
            String pluginId = fileName.replace("-1.0.0-repackage.zip", "");
            PluginInfo pluginInfo = pluginOperator.getPluginInfo(pluginId);
            if (pluginInfo == null) {
                Path path = Paths.get(dirPath + "/" + fileName);
                pluginOperator.load(path, true);
            }
        }
    }

    /**
     * 扫描指定文件夹下具有指定后缀的文件
     *
     * @param folderPath    文件夹路径
     * @param fileExtension 文件后缀，例如 ".txt"
     * @return 符合条件的文件名字列表
     */
    private List<String> scanFiles(String folderPath, String fileExtension) {
        List<String> fileNames = new ArrayList<>();
        File folder = new File(folderPath);
        // 检查文件夹是否存在且是一个有效的目录
        if (folder.exists() && folder.isDirectory()) {
            File[] files = folder.listFiles();
            if (files != null) {
                for (File file : files) {
                    if (file.isFile() && file.getName().endsWith(fileExtension)) {
                        fileNames.add(file.getName());
                    }
                }
            }
        }
        return fileNames;
    }


    @Override
    public Plugin findById(Long id) {
        return pluginRepository.findById(id).orElse(null);
    }

    @Override
    public Plugin findByPackageName(String packageName) {
        return pluginRepository.findByPackageName(packageName);
    }

    @Override
    public Plugin save(Plugin plugin) {
        return pluginRepository.save(plugin);
    }

    @Override
    public void delete(Long id) {
        pluginRepository.deleteById(id);
    }


    @Override
    @Transactional
    public boolean install(String pluginId) throws Exception {
        //TODO 远程下载安装（安装只是把插件load到插件目录去，并且加入数据库）
        String type = "plugins-feature";
        String fileName = "plugins-feature-seo-url-1.0.0-repackage.zip";
        String dirPath = PluginConfig.zipPath + "/" + type;
        File file = new File(dirPath + "/" + fileName);
        if (!file.exists()) {
            throw new Exception("插件下载失败");
        }
        Path path = Paths.get(dirPath + "/" + fileName);
        PluginInfo pluginInfo = pluginOperator.load(path, true);
        file.delete();//已经安装了，那就直接删除这个插件包
        if (pluginInfo != null) {
            Plugin plugin = findByPluginId(pluginId);
            if (plugin == null) {
                plugin = new Plugin();
                plugin.setPluginId(pluginInfo.getPluginId());
                plugin.setName(pluginInfo.getPluginDescriptor().getDescription());
                plugin.setDescription(pluginInfo.getPluginDescriptor().getDescription());
                plugin.setAuthor(pluginInfo.getPluginDescriptor().getProvider());
                plugin.setVersion(pluginInfo.getPluginDescriptor().getPluginVersion());
                plugin.setVersion(pluginInfo.getPluginDescriptor().getPluginVersion());
                //plugin.setConfig(JSON.toJSONString(pluginInfo.getExtensionInfo()));
                String packageName = pluginId + "-" + pluginInfo.getPluginDescriptor().getPluginVersion() + "-repackage" + ".zip";
                plugin.setPackageName(packageName);
                plugin.setEnabled(false);
                String pluginPath = pluginInfo.getPluginDescriptor().getPluginPath();
                for (PluginsTypeEnum pluginsTypeEnum : PluginsTypeEnum.values()) {
                    if (pluginPath.indexOf(File.separatorChar + pluginsTypeEnum.getPluginDir() + File.separatorChar) > -1) {
                        plugin.setType(pluginsTypeEnum.getPluginDir());
                        break;
                    }
                }
                pluginRepository.save(plugin);
            }
            return true;
        } else {
            return false;
        }

    }

    public void test(String pluginId) throws Exception {

        Path path = Paths.get("D:\\test\\jar\\plugins-feature-seo-url-1.0.0-repackage.zip");

        // pluginOperator.unload(pluginId);
        pluginOperator.load(path, true);
        pluginOperator.start(pluginId);
        Plugin plugin = findByPluginId(pluginId);
        if (plugin == null) {
            //pluginOperator.stop(pluginId);
            //pluginOperator.unload(pluginId);

            throw new Exception("插件不存在");
        }

        // 这里添加实际的插件安装逻辑
        // 比如下载插件文件、解压、复制到插件目录等
        throw new Exception("测试中");

        //plugin.setInstalled(true);
        //plugin.setEnabled(true);
        //save(plugin);
    }

    @Override
    @Transactional
    public boolean uninstall(String pluginId) throws Exception {
        Plugin plugin = findByPluginId(pluginId);
        if (plugin == null) {
            throw new Exception("插件不存在");
        }

        PluginInfo pluginInfo = pluginOperator.getPluginInfo(pluginId);
        if (pluginInfo != null) {
            pluginOperator.uninstall(plugin.getPluginId(), true, false);
        }


        pluginRepository.delete(plugin);
        return true;
    }

    @Override
    @Transactional
    public void enable(String pluginId) throws Exception {
        Plugin plugin = findByPluginId(pluginId);
        if (plugin == null) {
            throw new Exception("插件不存在");
        }

        plugin.setEnabled(true);
        save(plugin);

        boolean rs = pluginOperator.start(plugin.getPluginId());
        if (!rs) {
            throw new Exception("启动失败");
        }
    }

    @Override
    @Transactional
    public void disable(String pluginId) throws Exception {
        Plugin plugin = findByPluginId(pluginId);
        if (plugin == null) {
            throw new Exception("插件不存在");
        }

        plugin.setEnabled(false);
        save(plugin);

        boolean rs = pluginOperator.stop(plugin.getPluginId());
        if (!rs) {
            throw new Exception("停止失败");
        }
    }

    @Override
    @Transactional
    public void updateConfig(Long id, Map<String, Object> config) throws Exception {
        Plugin plugin = findById(id);
        if (plugin == null) {
            throw new Exception("插件不存在");
        }

        // 将配置转换为JSON字符串
        String configJson = objectMapper.writeValueAsString(config);
        plugin.setConfig(configJson);
        save(plugin);
    }

    @Override
    public Page<Plugin> getMarketPlugins(PageRequest pageRequest) {
        // 这里实现获取插件市场数据的逻辑
        // 可以是从远程服务器获取，或者从本地配置读取

        return null;
    }

    @Override
    public Plugin findByPluginId(String pluginId) {
        return pluginRepository.findByPluginId(pluginId);
    }

    @Override
    public void init(Plugin plugins) {

    }
} 